using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Awaiter;
using Nsb.Classes;
using Yoshi.Fb;
using YoshiBase.Classes;
using jQueryApi;

namespace Yoshi.Classes
{
    [IgnoreNamespace]
    public class ProfileData : SavableData
    {
        private static readonly string ProfilePartitionKey = Uri.DbPath("profile");
        internal static readonly Dictionary<string, YoshiUser> UserCache = new Dictionary<string, YoshiUser>();
        private string ProfileRowKey;
        public FeedData FeedData;
        private YoshiUser _yoshiUser;

        public YoshiUser My
        {
            get { return _yoshiUser ?? (_yoshiUser = new YoshiUser()); }
            set
            {
                FeedData = null;
                _yoshiUser = value;
                Formulas.NewIdPrefix = value.id;
                FbUser fbu = new FbUser();
                jQuery.Extend(true, fbu, value);
                Master.FbData.FbBaseUser = Master.FbUser = fbu;
                Master.FbData.FbBaseAuth = new FbAuth();
                Master.FbData.FbBaseAuth.access_token = "test";
                Master.Profile.Initialize(value.id);
            }
        }

        public string MyId
        {
            get { return String.IsNullOrEmpty(My.id) ? (Master.FbUser != null ? Master.FbUser.id : My.id) : My.id; }
        }

        public string MyAlias
        {
            get { return My.alias; }
            set { My.alias = value; }
        }
        /// <summary>
        /// Gets the feed list. Possible null return on empty feed.
        /// </summary>
        public List<FeedItem> FeedList
        {
            get { return FeedData == null ? new List<FeedItem>() : FeedData.Feed ?? new List<FeedItem>(); }
        }

        public void Initialize(string id)
        {
            Debug.Assert(!String.IsNullOrEmpty(id), "My.id is not null or empty");
            ProfileRowKey = id;
        }

        public static void LoadMyProfileAw(Await awp)
        {
            string myId = Master.Profile.MyId;
            ProfileData data = Master.Profile;
            YoshiUser usr = GetUserFromCacheById(myId);
            if (usr != null)
            {
                data.My = usr;
                awp.Done();
                return;
            }
            new Await()
                .AddAw(LoadProfileByIdAw, myId)
                .HandleDl(Exceptions.BlobLoadError,
                          delegate(Await aw)
                          {
                              usr = new YoshiUser();
                              jQuery.ExtendObject(true, usr, (YoshiUser) (object) Master.FbUser);
                              UserCache[myId] = usr;
                              data.My = usr;
                              data.Saved(false);
                              aw.Finish();
                              awp.Handle(new Exception(Exceptions.NewUser));
                          }
                )
                .AddDx(delegate
                       {
                           data.My = GetUserFromCacheById(myId);
                           if (String.IsNullOrEmpty(data.My.photo))
                           {
                               data.My.photo = Master.FbUser.PhotoUrl;
                               data.Saved(false);
                               data.SaveMyProfileAsync(Await.AsyncAw, ResultRx);
                           }
                           else
                               data.Saved(true);
                       })
                .Commit(awp);
        }

        public void SaveMyProfileAsync(Await awp, string rxKey)
        {
            if (!Saved())
            {
                Saved(true);

                new Await()
                    .AddDl(delegate(Await aw) { StoreBlobAw(aw, ProfilePartitionKey, ProfileRowKey, rxKey, My); })
                    .HandleDl(Exceptions.BlobSaveError, delegate { Saved(false); })
                    .Commit(awp);
            }
        }

        public void GetFeedAw(Await awp)
        {
            if (FeedData == null)
                FeedData = new FeedData();
            FeedData.GetFeedAw(awp);
        }

        public void AddToLocalFeed(FeedItem item)
        {
            if (FeedData != null)
            {
                FeedData.AddToLocalFeed(item);
            }
        }

        public void WriteToFeedAw(Await awp, string category, string msg)
        {
            new FeedData().WriteToFeedAw(awp, category, msg);
        }

        public void SaveFeedAw(Await awp)
        {
            if (FeedData != null)
                FeedData.SaveFeedAw(awp);
            else
                awp.Done();
        }

        public static void GetUserByIdAw(Await awp, string id)
        {
            new Await()
                .AddDx(
                    delegate(Await aw)
                    {
                        YoshiUser usr = GetUserFromCacheById(id);
                        if (usr != null)
                        {
                            awp[ResultRx] = usr;
                            aw.Finish();
                        }
                    })
                .AddAw(LoadProfileByIdAw, id)
                .Commit(awp);
        }

        public static YoshiUser GetUserFromCacheById(string id)
        {
            return UserCache[id];
        }

        public static void LoadProfileByIdAw(Await awp, string id)
        {
            //Inform.Debug("LoadProfileByIdAw id={0}", id);
            string rowKey = id;
            new Await()
                .AddDl(delegate(Await aw) { RetrieveBlobAw(aw, ProfilePartitionKey, rowKey); })
                .HandleDl(Exceptions.BlobLoadError, Await.RethrowAw)
                .AddDx(
                    delegate(Await aw)
                    {
                        YoshiUser usr = (YoshiUser) aw[ResultRx];
                        if (Script.IsValue(usr))
                        {
                            YoshiUser u = new YoshiUser();
                            jQuery.Extend(u, usr);
                            UserCache[id] = u;
                            aw[ResultRx] = u;
                        }
                    })
                .Commit(awp);
        }

        public static void SearchForUsersAw(Await awp, object attributes)
        {
            new Await()
                .AddAw(GetDirAw, Uri.DbPath("profile"))
                .HandleDl(Exceptions.BlobLoadError, Await.RethrowAw)
                .AddDx(
                    delegate(Await aw)
                    {
                        Dictionary result = (Dictionary)aw[ResultRx];

                        List<string> files = (List<string>)result["files"];
                        List<string> ids = new List<string>();
                        foreach (string fi in files)
                        {
                            ids.Add(fi.Split(".")[0]);
                        }
                        awp[ResultRx] = ids;
                    })
                .Commit(awp);
        }
    }
}